package com.nulldev.util.web.YouTubeExtractor.subtitles;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.WritableByteChannel;
import java.util.List;
import java.util.concurrent.TimeUnit;

import com.nulldev.util.concurrency.threadIt.v4.emapi.ExecutorManager;
import com.nulldev.util.concurrency.threadIt.v4.emapi.uft.Executable;
import com.nulldev.util.data.Variables;
import com.nulldev.util.io.extensions.copyable.Copyable;
import com.nulldev.util.io.extensions.copyable.nio.NIOCopyable;
import com.nulldev.util.languages.json.uniapi.UniJsonValue;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.web.YouTubeExtractor.subtitles.Subtitle.SubtitleStyle;

public class JSCSSBuilder implements Copyable, NIOCopyable {

	/*
	 * TODO: For 2.2.x: Add the JSON based (CSS formatted) subtitle builder.
	 * 
	 * FIXME: - We still generate <c.CLASSNAME></c>, is this a good idea? -
	 * Timestamps/duration seems to be not in float format.
	 * 
	 * This will be used by nTube for styled video transcriptions. (Also I came up
	 * with the idea first, fuck you YouTube.)
	 */

	public static final String VERSION = "1.0.0";
	private static final Logger log = LoggerFactory.getLogger();
	private int index = 1;

	private final UniJsonValue output_obj;
	private final UniJsonValue entries;

	public JSCSSBuilder() {
		this.output_obj = UniJsonValue.object();
		this.output_obj.add("js_css_version", VERSION);
		this.entries = UniJsonValue.array();
	}

	public JSCSSBuilder add(final Subtitle sub) {
		Variables.requireNonNull(sub, "sub");
		final UniJsonValue entry = UniJsonValue.object();
		entry.add("index", this.index);
		entry.add("text", sub.text());
		entry.add("start", sub.start());
		entry.add("end", sub.end());
		if (sub.hasStyles()) {
			final List<SubtitleStyle> ss = sub.getStyles();
			final UniJsonValue style = UniJsonValue.object();
			ss.forEach((_style) -> {
				if (_style.hasBackgroundAlpha())
					style.add("backgroundAlpha", _style.backgroundAlpha);
				if (_style.hasColor())
					style.add("color", _style.color);
				if (_style.hasEdgeColor())
					style.add("edgeColor", _style.edgeColor);
				if (_style.hasFontFamily())
					style.add("fontFamily", _style.fontFamily);
				if (_style.hasForegroundAlpha())
					style.add("foregroundAlpha", _style.foregroundAlpha);
				if (_style.hasTextIdentifier())
					style.add("textIdentifier", _style.textIdf);
				if (_style.hasTextSizeIncrement())
					style.add("textSizeIncrement", _style.textSizeIncrement);
			});
			entry.add("styling", style);
		}
		this.entries.add(entry);
		this.index++;
		return this;
	}

	public void addAll(final List<Subtitle> subtitles) {
		if (subtitles == null || subtitles.isEmpty())
			return;
		final Executable<?> f = ExecutorManager.make(() -> {
			for (final Subtitle subtitle : subtitles) {
				this.add(subtitle);
			}
			return null;
		});
		WebVTTBuilder.APPEND_ACCELERATOR.asyncSubmit(f).waitFor(60, TimeUnit.SECONDS);
	}

	public void finish() {
		this.output_obj.add("entries", entries);
	}

	public String build() {
		return this.output_obj.toString();
	}

	public UniJsonValue get() {
		return this.output_obj;
	}

	@Override
	public void writeTo(final OutputStream os) throws IOException {
		this.output_obj.writeTo(Variables.requireNonNullObject(os, "os"));
	}

	@Override
	public void writeTo(final WritableByteChannel os) throws IOException {
		this.output_obj.writeTo(Variables.requireNonNullObject(os, "os"));
	}
}
